package controller.webservice;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;

import net.sf.json.JSONObject;

import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;

import exception.InputValidationErrors;

/**
 * JsonRequest entity to encapsulate and validate the JSON request received via
 * Web Service. E.g. Valid Dump User Request: {"userid":"amy.ng.2012"}; Invalid
 * Dump User Request {"userid:""} or {}
 * 
 * @author jaslin.wee.2012, huangjm.2012
 * 
 */
class JsonRequestParser {

	private JSONObject jsonRequestObj = new JSONObject();
	private String[] expectedFields;

	/**
	 * Constructor. Validates the given JSON request string.
	 * 
	 * @param request
	 *            the JSON request String
	 * @param expectedFields
	 *            a list of expected field names to be found in the JSON Request
	 * @throws InputValidationErrors
	 *             if there is an error in parsing the JSON request string, a
	 *             field is blank or an expected field is missing
	 */
	JsonRequestParser(String request, String... expectedFields)
			throws InputValidationErrors {

		if (request == null) {
			throw new InputValidationErrors("r parameter value is required");
		}

		try {

			// 1. parse the request string
			// 2. obtain a map of field-value pairs
			Map<?, ?> parsedRequest = (Map<?, ?>) JSONValue
					.parseWithException(request);

			// 3. put all field-value pairs into the JSON Request Object
			jsonRequestObj.putAll(parsedRequest);

		} catch (ParseException pe) {
			// error parsing JSON request string
			throw new InputValidationErrors("JSON request is malformed");
		}

		this.expectedFields = expectedFields;

		validateJsonRequest();
	}

	/**
	 * Validates the JSON request object for missing fields or blank values.
	 * 
	 * @throws InputValidationErrors
	 *             if a field is blank or an expected field is missing
	 */
	private void validateJsonRequest() throws InputValidationErrors {
		ArrayList<String> errors = new ArrayList<String>();

		// validate every expected field of the JSON request
		for (String eachField : expectedFields) {

			Object value = jsonRequestObj.get(eachField);
			if (value == null) {
				// cannot find the given field
				errors.add(eachField + " is missing");
			} else {
				// can find a value for the given field

				// convert value to String and check if value is blank
				if (String.valueOf(value).isEmpty()) {
					// value is blank
					errors.add(eachField + " is blank");
				} else {
					// no errors =)
				}
			}

		}

		// check for error messages in the array list
		if (!errors.isEmpty()) {
			// sort errors in alphabetical order
			Collections.sort(errors);

			throw new InputValidationErrors(errors);
		}

	}

	/**
	 * Returns the validated JSON request.
	 * 
	 * @return a JSONObject representing the validated JSON request.
	 */
	JSONObject getRequest() {
		return jsonRequestObj;
	}

}
